home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / IATHREAD.PAK / MDICHILD.C < prev    next >
C/C++ Source or Header  |  1997-05-06  |  15KB  |  496 lines

  1. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  2. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  3. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  4. // PARTICULAR PURPOSE.
  5. //
  6. // Copyright (C) 1993-1995  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  MODULE:   mdichild.c
  9. //
  10. //  PURPOSE:
  11. //    To implement the basic mdi child commands.
  12. //
  13. //  FUNCTIONS:
  14. //    ChildThreadProc    - Performs work for each MDI child window.
  15. //    MDIChildWndProc    - Processes messages for MDI child windows.
  16. //    MsgMCCommand       - Handle the WM_COMMAND messages for MDI children.
  17. //    MsgMCCreate        - Initializes new MDI child window.
  18. //    MsgMCDestroy       - Destroys MDI child window and frees its resources.
  19. //    MsgMCMdiActiveate  - Changes menus depending on which child is active.
  20. //    CmdMCThreadSuspend - Suspends active MDI child's worker thread.
  21. //    CmdMCThreadResume  - Resumes active MDI child's worker thread.
  22. //
  23. //  COMMENTS:
  24. //
  25.  
  26.  
  27. #include <windows.h>            // required for all Windows applications
  28. #include <windowsx.h>
  29. #include "globals.h"            // prototypes specific to this application
  30. #include <stdlib.h>
  31. #include "resource.h"
  32.  
  33. // Child window message table definition.
  34. static MSD rgmsd[] =
  35. {
  36.     {WM_COMMAND,     MsgMCCommand},
  37.     {WM_CREATE,      MsgMCCreate},
  38.     {WM_MDIACTIVATE, MsgMCMdiActivate},
  39.     {WM_DESTROY,     MsgMCDestroy}
  40. };
  41.  
  42. static MSDI msdiChild =
  43. {
  44.     sizeof(rgmsd) / sizeof(MSD),
  45.     rgmsd,
  46.     edwpMDIChild
  47. };
  48.  
  49.  
  50. // Child window command table definition.
  51. static CMD rgcmd[] =
  52. {
  53.     {IDM_THREAD_PRIORITY,   CmdMCThreadPriority},
  54.     {IDM_THREAD_SUSPEND,    CmdMCThreadSuspend},
  55.     {IDM_THREAD_RESUME,     CmdMCThreadResume}
  56. };
  57.  
  58. static CMDI cmdiChild =
  59. {
  60.     sizeof(rgcmd) / sizeof(CMD),
  61.     rgcmd,
  62.     edwpMDIChild
  63. };
  64.  
  65.  
  66. //
  67. //  FUNCTION: ChildThreadProc(LPDWORD)
  68. //
  69. //  PURPOSE:  To perform work for each MDI child window.
  70. //
  71. //  PARAMETERS:
  72. //
  73. //
  74. //  RETURN VALUE:
  75. //    Always returns 0.
  76. //
  77. //  COMMENTS:
  78. //    This function executes in one thread for each MDI child window.
  79. //
  80. //
  81.  
  82. #pragma warn -rch
  83. DWORD WINAPI ChildThreadProc (LPDWORD lpData)
  84. {
  85.     PTHREAD_DATA pThreadData = (PTHREAD_DATA)lpData;
  86.      HWND         hWnd;
  87.      HDC          hDrawDC;
  88.     RECT         rClientRect = {0};
  89.      HBRUSH       hRectBrush;
  90.      HBRUSH       hOldBrush;
  91.      COLORREF     crRectColor;
  92.     int          nRed, nGreen, nBlue;
  93.     int          nLeft, nTop, nRight, nBottom;
  94.  
  95.  
  96.      nGreen = nBlue = 0;
  97.  
  98.      while (TRUE)
  99.     {
  100.         EnterCriticalSection(&(pThreadData -> csCritSec));
  101.  
  102.           if (pThreadData -> bKill == TRUE)
  103.         {
  104.                 // Be sure to leave critical section before exiting!
  105.             LeaveCriticalSection (&(pThreadData -> csCritSec));
  106.                 ExitThread(0);
  107.         }
  108.  
  109.         // Check timeout counter and reduce this thread's priority and
  110.         // the process's priority class if needed.  This prevents this
  111.         // thread/process from hogging the system.
  112.         ReducePriority (pThreadData);
  113.  
  114.  
  115.         // Draw rectangles in MDI child window only if it's client
  116.         // area is at least 1 pixel wide and 1 pixel tall.
  117.         hWnd = pThreadData -> hWindow;
  118.         hDrawDC = GetDC(hWnd);
  119.         GetClientRect(hWnd, &rClientRect);
  120.  
  121.         if ((rClientRect.right != 0) && (rClientRect.bottom != 0))
  122.         {
  123.                 // Pick a random pure color for the rectangle.
  124.             // Below is a more-optimized version of this:
  125.             //    nRed   = rand() % 0xFF;
  126.             //    nGreen = rand() % 0xFF;
  127.             //    nBlue  = rand() % 0xFF;
  128.  
  129.             nRed   = nGreen;
  130.             nGreen = nBlue;
  131.             nBlue  = rand() % 0xFF;
  132.  
  133.             crRectColor = RGB(nRed, nGreen, nBlue);
  134.  
  135.             hRectBrush = CreateSolidBrush(
  136.                                           GetNearestColor(hDrawDC,
  137.                                                           crRectColor)
  138.                                          );
  139.             hOldBrush = SelectObject(hDrawDC, hRectBrush);
  140.  
  141.             // Draw the rectangle
  142.             nLeft   = rand() % rClientRect.right;
  143.             nTop    = rand() % rClientRect.bottom;
  144.                 nRight  = nLeft + 20;
  145.             nBottom = nTop + 20;
  146.             Rectangle(hDrawDC, nLeft, nTop, nRight, nBottom);
  147.  
  148.             // Clean up all of the resources used to draw rectangle.
  149.             SelectObject(hDrawDC, hOldBrush);
  150.             ReleaseDC(hWnd, hDrawDC);
  151.             DeleteObject(hRectBrush);
  152.  
  153.             // Be sure to leave the critical section before exiting
  154.             // the while loop!
  155.             LeaveCriticalSection(&(pThreadData -> csCritSec));
  156.         }
  157.         else
  158.         {
  159.             // Go to sleep temporarily while MDI child is minimized or has no
  160.             // client area.
  161.  
  162.             // Leave the critical section before sleeping.  No need to
  163.             // hold it while sleeping.  Note that we also have to leave the
  164.             // critical section at the end of the if() clause above.
  165.                 LeaveCriticalSection(&(pThreadData -> csCritSec));
  166.  
  167.                 Sleep(1000);
  168.           }
  169.      }
  170.      return 0;
  171. }
  172. #pragma warn .rch
  173.  
  174.  
  175. //
  176. //  FUNCTION: MDIChildWndProc(HWND, UINT, WPARAM, LPARAM)
  177. //
  178. //  PURPOSE:  Processes messages for MDI child windows.
  179. //
  180. //  PARAMETERS:
  181. //    hwnd     - window handle
  182. //    uMessage - message number
  183. //    wparam   - additional information (depends on message)
  184. //    lparam   - additional information (depends on message)
  185. //
  186. //  RETURN VALUE:
  187. //    Depends on the message number.
  188. //
  189. //  COMMENTS:
  190. //    Dispatch all messages sent to MDI child windows.
  191. //
  192.  
  193. LRESULT CALLBACK MDIChildWndProc(HWND   hwnd,
  194.                                  UINT   uMessage,
  195.                                  WPARAM wparam,
  196.                                  LPARAM lparam)
  197. {
  198.     return DispMessage( &msdiChild, hwnd, uMessage, wparam, lparam );
  199. }
  200.  
  201.  
  202. //
  203. //  FUNCTION: MsgMCCommand(HWND, UINT, WPARAM, LPARAM)
  204. //
  205. //  PURPOSE: Handle the WM_COMMAND messages for MDI children.
  206. //
  207. //  PARAMETERS:
  208. //    hwnd     - window handle
  209. //    uMessage - WM_COMMAND (Unused)
  210. //    wparam   - Contains command-specific information
  211. //    lparam   - Contains command-specific information
  212. //
  213. //  RETURN VALUE:
  214. //
  215. //  COMMENTS:
  216. //    Dispatch all commands sent to MDI child windows.
  217. //
  218.  
  219. #pragma argsused
  220. LRESULT MsgMCCommand(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  221. {
  222.      return DispCommand(&cmdiChild, hwnd, wparam, lparam);
  223. }
  224.  
  225.  
  226. //
  227. //  FUNCTION: MsgMCCreate(HWND, UINT, WPARAM, LPARAM)
  228. //
  229. //  PURPOSE:  Initializes new child window and starts its worker thread.
  230. //
  231. //  PARAMETERS:
  232. //    hwnd     - The window being created.
  233. //    uMessage - WM_CREATE             (unused).
  234. //    wparam   - Message specific data (unused).
  235. //    lparam   - Message specific data (unused).
  236. //
  237. //  RETURN VALUE:
  238. //    Always returns 0 - message handled.
  239. //
  240. //  COMMENTS:
  241. //
  242.  
  243. #pragma argsused
  244. LRESULT MsgMCCreate(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  245. {
  246.      PTHREAD_DATA  pThreadData;
  247.      HANDLE        hThread;
  248.     DWORD         dwThreadID  = 0;
  249.  
  250.  
  251.     // Allocate thread data block.  If allocation fails, force window
  252.     // creation failure.
  253.     pThreadData = AllocThreadData();
  254.     if (pThreadData == NULL)
  255.         return -1;
  256.  
  257.  
  258.     // Create the child window thread suspended.  This will ensure that
  259.     // the new thread doesn't try to access any of the members of the
  260.     // thread data before all members have been initialized.
  261.      // If thread couldn't be created, clean up critical section, allocated
  262.      // memory, and force window creation failure.
  263.     hThread = CreateThread(NULL,
  264.                            0,
  265.                            (LPTHREAD_START_ROUTINE) ChildThreadProc,
  266.                            (LPVOID)pThreadData,
  267.                            CREATE_SUSPENDED,
  268.                            &dwThreadID);
  269.     if (hThread == NULL)
  270.     {
  271.         DeleteCriticalSection(&(pThreadData -> csCritSec));
  272.         FreeThreadData(pThreadData);
  273.         return -1;
  274.     }
  275.  
  276.     // Initialize all thread block members
  277.     InitializeCriticalSection(&(pThreadData -> csCritSec));
  278.     pThreadData -> hWindow    = hwnd;
  279.     pThreadData -> bKill      = FALSE;
  280.     pThreadData -> hThread    = hThread;
  281.     pThreadData -> dwThreadID = dwThreadID;
  282.     pThreadData -> nPriorityTimer = -1;     // Timer initially deactivated
  283.  
  284.     // Store a pointer to the thread data block in the extra bytes for
  285.     // convenient access.
  286.     SetWindowLong(hwnd, GWL_USERDATA, (long)pThreadData);
  287.  
  288.     ResumeThread(hThread);
  289.  
  290.     gcOpenChildWnds++;
  291.  
  292.      return 0;
  293. }
  294.  
  295.  
  296. //
  297. //  FUNCTION: MsgMCDestroy(HWND, UINT, WPARAM, LPARAM)
  298. //
  299. //  PURPOSE: To handle the WM_DESTROY message sent to MDI child windows.
  300. //
  301. //  PARAMETERS:
  302. //    hwnd     - The window being destroyed.
  303. //    uMessage - WM_DESTROY            (unused).
  304. //    wparam   - Message specific data (unused).
  305. //    lparam   - Message specific data (unused).
  306. //
  307. //  RETURN VALUE:
  308. //    Always returns 0 - message handled.
  309. //
  310. //  COMMENTS:
  311. //
  312.  
  313. #pragma argsused
  314. LRESULT MsgMCDestroy(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)
  315. {
  316.      PTHREAD_DATA pThreadData;
  317.      HANDLE       hThread;
  318.      BOOL         fResumed;
  319.  
  320.      // Get thread data block associated with this child window
  321.      pThreadData = (PTHREAD_DATA)GetWindowLong(hwnd, GWL_USERDATA);
  322.  
  323.     if (pThreadData != NULL)  // Should never be NULL. ASSERT better!
  324.     {
  325.         EnterCriticalSection (&(pThreadData -> csCritSec));
  326.  
  327.         // Tell thread that it is time to exit
  328.         pThreadData -> bKill = TRUE;
  329.         hThread = pThreadData -> hThread;
  330.  
  331.         LeaveCriticalSection(&(pThreadData -> csCritSec));
  332.  
  333.         // Make sure thread is running before we wait for it to exit.
  334.         do
  335.         {
  336.             fResumed = ResumeThread(hThread);
  337.         }
  338.         while (fResumed != 0xFFFFFFFF && fResumed > 1);
  339.  
  340.  
  341.         // Wait for thread to exit before closing its handle and deleting
  342.         // the thread data block.
  343.         WaitForSingleObject(hThread, INFINITE);
  344.  
  345.         CloseHandle(hThread);
  346.         DeleteCriticalSection(&(pThreadData -> csCritSec));
  347.         FreeThreadData(pThreadData);
  348.     }
  349.  
  350.     // Decrement number of open MDI child windows.
  351.     gcOpenChildWnds--;
  352.  
  353.     return 0;
  354. }
  355.  
  356.  
  357. //
  358. //  FUNCTION: MsgMCMdiActivate(HWND, UINT, WPARAM, LPARAM)
  359. //
  360. //  PURPOSE:  To change the menu on the frame window so that it is the right
  361. //            one for the MDI child window.
  362. //
  363. //  PARAMETERS:
  364. //    hwnd     - The window handing the message.
  365. //    uMessage - WM_MDIACTIVATE        (unused).
  366. //    wparam   - The MDI child window becoming inactive (unused).
  367. //    lparam   - The MDI child window becoming active.
  368. //
  369. //  RETURN VALUE:
  370. //    Always returns 0 - message handled.
  371. //
  372. //  COMMENTS:
  373. //    If the window becoming active is an MDI chil window, set the menu to
  374. //    document menu; otherwise, set it to the initial frame menu.
  375. //
  376.  
  377. #pragma argsused
  378. LRESULT MsgMCMdiActivate(HWND   hwnd,
  379.                          UINT   uMessage,
  380.                          WPARAM wparam,
  381.                          LPARAM lparam)
  382. {
  383.     HWND  hActiveWnd     = (HWND)lparam;     // Window becoming active
  384.      HMENU hNewMenu;
  385.      HMENU hNewWindowMenu;
  386.  
  387.     // If this window is becoming active, set the menu to document window;
  388.     // otherwise set it to the initial frame window.
  389.     if (hwnd == hActiveWnd)
  390.     {
  391.         hNewMenu       = ghDocMenu;
  392.         hNewWindowMenu = GetSubMenu (ghDocMenu, DOCWINDOWMENU);
  393.     }
  394.     else
  395.     {
  396.         hNewMenu       = ghInitMenu;
  397.         hNewWindowMenu = GetSubMenu (ghInitMenu, INITWINDOWMENU);
  398.     }
  399.     SendMessage (ghwndMDIClient,
  400.                  WM_MDISETMENU,
  401.                  (WPARAM)hNewMenu,
  402.                  (LPARAM)hNewWindowMenu);
  403.     DrawMenuBar (ghwndFrame);
  404.  
  405.     return 0;
  406. }
  407.  
  408.  
  409. //
  410. //  FUNCTION: CmdMCThreadSuspend(HWND, WORD, WORD, HWND)
  411. //
  412. //  PURPOSE: To suspend the thread associated with a given child window.
  413. //
  414. //  PARAMETERS:
  415. //    hwnd      - The window handling the command.
  416. //    wCommand  - IDM_THREAD_SUSPEND  (unused).
  417. //    wNotify   - Notification number (unused)
  418. //    hwndCtrl  - NULL                (unused).
  419. //
  420. //  RETURN VALUE:
  421. //    Always returns 0 - command handled.
  422. //
  423. //  COMMENTS:
  424. //
  425.  
  426. #pragma argsused
  427. LRESULT CmdMCThreadSuspend(HWND hwnd,
  428.                            WORD wCommand,
  429.                            WORD wNotify,
  430.                            HWND hwndCtrl)
  431. {
  432.      PTHREAD_DATA pThreadData;
  433.  
  434.  
  435.     pThreadData = (PTHREAD_DATA)GetWindowLong(hwnd, GWL_USERDATA);
  436.  
  437.     if (pThreadData != NULL)      // Should never be NULL  ASSERT better
  438.     {
  439.         EnterCriticalSection(&(pThreadData -> csCritSec));
  440.  
  441.         // Call SuspendThread inside critical section to make sure thread
  442.         // is not in the critical section.  Otherwise, a deadlock will occur
  443.         // if you suspend the thread while it is in the critical section and
  444.         // try to claim the critical section before the thread is resumed.
  445.         SuspendThread(pThreadData -> hThread);
  446.  
  447.         LeaveCriticalSection(&(pThreadData -> csCritSec));
  448.      }
  449.     return 0;
  450. }
  451.  
  452.  
  453. //
  454. //  FUNCTION: CmdMCThreadResume(HWND, WORD, WORD, HWND)
  455. //
  456. //  PURPOSE: To resume the thread associated with a given child window.
  457. //
  458. //  PARAMETERS:
  459. //    hwnd      - The window handling the command.
  460. //    wCommand  - IDM_THREAD_RESUME   (unused).
  461. //    wNotify   - Notification number (unused)
  462. //    hwndCtrl  - NULL                (unused).
  463. //
  464. //  RETURN VALUE:
  465. //    Always returns 0 - command handled.
  466. //
  467. //  COMMENTS:
  468. //
  469. //
  470.  
  471. #pragma argsused
  472. LRESULT CmdMCThreadResume(HWND hwnd,
  473.                           WORD wCommand,
  474.                           WORD wNotify,
  475.                           HWND hwndCtrl)
  476. {
  477.     PTHREAD_DATA pThreadData;
  478.      HANDLE       hThread;
  479.  
  480.  
  481.     pThreadData = (PTHREAD_DATA)GetWindowLong(hwnd, GWL_USERDATA);
  482.  
  483.     if (pThreadData != NULL)      // Should never be NULL  ASSERT better
  484.     {
  485.         // Get thread's handle.  Use critical section in case thread
  486.         // is not suspended.  Suspended thread won't be in critical section
  487.         // because we suspended it while we were in the critical section.
  488.         EnterCriticalSection(&(pThreadData -> csCritSec));
  489.         hThread = pThreadData -> hThread;
  490.         LeaveCriticalSection(&(pThreadData -> csCritSec));
  491.  
  492.         ResumeThread (hThread);
  493.      }
  494.     return 0;
  495. }
  496.